package com.clinic.action.appointment;

import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;

import com.clinic.action.common.AuthenticationAction;
//import com.clinic.action.common.AbstractAction.ActionResult;
import com.clinic.entity.gui.GuiAppointment;
import com.clinic.entity.gui.GuiPagination;
import com.clinic.entity.gui.GuiPatient;
import com.clinic.entity.param.Index;
import com.clinic.entity.type.AppointmentTime;
import com.clinic.logic.appointment.AppointmentLogic;
import com.clinic.logic.user.PatientLogic;
import com.clinic.util.CommonUtil;

public class AppointmentAction extends AuthenticationAction {

	private static final long serialVersionUID = 568747665427831022L;
	
	@Autowired
	private PatientLogic patientLogic;
	
	@Autowired
	private AppointmentLogic appointmentLogic;
	
	private long id;
	private long patientId;
	private GuiPatient guiPatient;
	private String aptDate;
	private String aptTime;
	private String aptNextDate;
	private String aptPrevDate;
	private GuiAppointment guiAppointment;
	private List<GuiAppointment> guiAppointmentList;
	private Map<Integer, Map<String, GuiAppointment>> dayAppointmentMap;
	private Map<Integer, List<GuiAppointment>> monthAppointmentMap;
	
	private int page;
	private List<GuiPatient> guiPatientList;
	private GuiPagination guiPagination;
	
	public String registration(){
		if(isDoctorLogin() || isAssistantLogin()) {
			Date appointmentDate = CommonUtil.getDateTimeByDateAndTime(aptDate, aptTime);
			boolean isFutureDateTime = CommonUtil.isTodayOrFutureDateTime(appointmentDate);
			if (isFutureDateTime){
				guiAppointment = new GuiAppointment();
				guiAppointment.setDate(aptDate);
				guiAppointment.setTime(aptTime);
				
				Index index = CommonUtil.getIndexBypage(page);
				
				List<GuiAppointment> upComingAppointments = appointmentLogic.getFutureOrOnDateAppointments(CommonUtil.getTodayDate(), new Index(1000));
				Set<Long> userIds = new HashSet<>();
				for (GuiAppointment oGuiAppointment : upComingAppointments) {
					userIds.add(oGuiAppointment.getPatient().getUserId());
				}
				
				if(userIds.size() > 0){
					guiPatientList = patientLogic.getPatientsNotInIds(userIds, index);
				} else {
					guiPatientList = patientLogic.getPatientList(index);
				}	
				guiPagination = patientLogic.getPaginationOfPatients(page, userIds.size());
				return SUCCESS;
			}
			return ERROR;
		}
		return ActionResult.AUTH_FAILED;
	}
	
	public String show(){
		if(isDoctorLogin() || isAssistantLogin()) {
			if (StringUtils.isNotBlank(aptDate)) {
				guiAppointmentList = appointmentLogic.getDayAppointmentListByDate(CommonUtil.getDateByStringFormat(aptDate));
				dayAppointmentMap = appointmentLogic.getDayAppointmentMapByAppointmentList(guiAppointmentList);
			} else {
				Date date = CommonUtil.getTodayDate();
				guiAppointmentList = appointmentLogic.getMonthAppointmentListByDate(date);
				monthAppointmentMap = appointmentLogic.getMonthAppointmentMapByAppointmentList(guiAppointmentList, date);
			}
			return SUCCESS;
		}
		return ActionResult.AUTH_FAILED;
	}

	public String edit(){
		if(isDoctorLogin() || isAssistantLogin()) {
			if (id > 0) {
				guiAppointment = appointmentLogic.getAppointmentDetailsById(id);
				Date oAptDate = CommonUtil.getDateByStringFormat(aptDate);
				aptNextDate = appointmentLogic.getNextDateString(oAptDate);
				if (CommonUtil.isFutureDateTime(oAptDate)) {
					aptPrevDate = appointmentLogic.getPrevDateString(oAptDate);
				}
				guiAppointmentList = appointmentLogic.getDayAppointmentListByDate(oAptDate);
				dayAppointmentMap = appointmentLogic.getDayAppointmentMapByAppointmentList(guiAppointmentList);
				return SUCCESS;
			}
			return ERROR;
		}
		return ActionResult.AUTH_FAILED;
	}

	public String delete(){
		if(isDoctorLogin() || isAssistantLogin()) {
			if (id > 0) {
				guiAppointment = appointmentLogic.getAppointmentDetailsById(id);
				aptDate = guiAppointment.getDate();
				appointmentLogic.deleteAppointmentDetailsById(id);
				return SUCCESS;
			}
			return ERROR;
		}
		return ActionResult.AUTH_FAILED;
	}
	
	public String insert() {
		// TODO cannot insert same day multi appointments
		if(isDoctorLogin() || isAssistantLogin()) {
			Date aDate = CommonUtil.getDateByStringFormat(guiAppointment.getDate());
			if (CommonUtil.getDaysLeftfromToday(aDate) >= 0) { // appointment valid only for future days
				boolean isAvailableAppointmentTime = appointmentLogic.isAvailableAppointmentTime(guiAppointment.getDate(), guiAppointment.getTime());
				GuiAppointment patientAppointment = appointmentLogic.getPatientAppointmentByDate(guiAppointment.getPatient().getUserId(), aDate);
				if (isAvailableAppointmentTime && patientAppointment.isNotAvailable()) {
					guiAppointment = appointmentLogic.insertAppointment(guiAppointment);
					aptDate = guiAppointment.getDate();
					return SUCCESS;
				}
			} 			
			patientId = guiAppointment.getPatient().getUserId();
			return ERROR;
		}
		return ActionResult.AUTH_FAILED;
	}

	public String update() {
		if(isDoctorLogin() || isAssistantLogin()) {
			Date aDate = CommonUtil.getDateByStringFormat(guiAppointment.getDate());
			if (CommonUtil.getDaysLeftfromToday(aDate) >= 0) { // appointment valid only for future days
				GuiAppointment patientAppointment = appointmentLogic.getPatientAppointmentByDate(guiAppointment.getPatient().getUserId(), aDate);
				boolean isPatientCurrentAppointment =
						patientAppointment.isAvailable() && (patientAppointment.getAppointmentId() == guiAppointment.getAppointmentId());
				
				boolean isAvailableAppointmentTime = appointmentLogic.isAvailableAppointmentTime(guiAppointment.getDate(), guiAppointment.getTime());
				if (isPatientCurrentAppointment || (patientAppointment.isNotAvailable() && isAvailableAppointmentTime)) {
					guiAppointment = appointmentLogic.updateAppointment(guiAppointment);
					aptDate = guiAppointment.getDate();
					return SUCCESS;
				}
			}
			id = guiAppointment.getAppointmentId();
			return ERROR;
		}
		return ActionResult.AUTH_FAILED;
	}
	
	public String list() {
		if(isDoctorLogin() || isAssistantLogin()) {
			if (patientId > 0) {
				guiPatient = patientLogic.getPatientDetailsById(patientId);
				if (guiPatient.isAvailable()) {
					guiAppointmentList = appointmentLogic.getAppointmentListByPatient(patientId, new Index(100));
				}
			} else {
				Date appointmentDate = null;
				if(StringUtils.isBlank(aptDate)) {
					appointmentDate = CommonUtil.getTodayDate();
				}else{
					appointmentDate = CommonUtil.getDateByStringFormat(aptDate);
				}
				aptDate = CommonUtil.getDateStringFormatByDate(appointmentDate);
				aptNextDate = appointmentLogic.getNextDateString(appointmentDate);
				aptPrevDate = appointmentLogic.getPrevDateString(appointmentDate);
				
				guiAppointmentList = appointmentLogic.getDayAppointmentListByDate(appointmentDate);
				dayAppointmentMap = appointmentLogic.getDayAppointmentMapByAppointmentList(guiAppointmentList);
			}
			return SUCCESS;
		}
		return ActionResult.AUTH_FAILED;
	}
	
	public AppointmentTime[] getAppointmentTimes() {
		return AppointmentTime.values();
	}
	
	public boolean isTodayOrFutureAppointmentDateTime() {
		return CommonUtil.isTodayOrFutureDateTime(CommonUtil.getDateByStringFormat(aptDate));
	}
	
	public long getId() {
		return id;
	}

	public void setId(long id) {
		this.id = id;
	}

	public long getPatientId() {
		return patientId;
	}

	public void setPatientId(long patientId) {
		this.patientId = patientId;
	}

	public GuiPatient getGuiPatient() {
		return guiPatient;
	}

	public void setGuiPatient(GuiPatient guiPatient) {
		this.guiPatient = guiPatient;
	}

	public String getAptDate() {
		return aptDate;
	}

	public void setAptDate(String aptDate) {
		this.aptDate = aptDate;
	}

	public String getAptTime() {
		return aptTime;
	}

	public void setAptTime(String aptTime) {
		this.aptTime = aptTime;
	}
	
	public boolean isExistAptNextDate() {
		return StringUtils.isNotBlank(getAptNextDate());
	}

	public String getAptNextDate() {
		return aptNextDate;
	}

	public void setAptNextDate(String aptNextDate) {
		this.aptNextDate = aptNextDate;
	}

	public boolean isExistAptPrevDate() {
		return StringUtils.isNotBlank(getAptPrevDate());
	}
	
	public String getAptPrevDate() {
		return aptPrevDate;
	}

	public void setAptPrevDate(String aptPrevDate) {
		this.aptPrevDate = aptPrevDate;
	}

	public GuiAppointment getGuiAppointment() {
		return guiAppointment;
	}

	public void setGuiAppointment(GuiAppointment guiAppointment) {
		this.guiAppointment = guiAppointment;
	}

	public List<GuiAppointment> getGuiAppointmentList() {
		return guiAppointmentList;
	}

	public void setGuiAppointmentList(List<GuiAppointment> guiAppointmentList) {
		this.guiAppointmentList = guiAppointmentList;
	}

	public boolean isExistDayAppointmentMap() {
		return dayAppointmentMap != null;
	}

	public Map<Integer, Map<String, GuiAppointment>> getDayAppointmentMap() {
		return dayAppointmentMap;
	}

	public void setDayAppointmentMap(
			Map<Integer, Map<String, GuiAppointment>> dayAppointmentMap) {
		this.dayAppointmentMap = dayAppointmentMap;
	}

	public int getPage() {
		return page;
	}

	public void setPage(int page) {
		this.page = page;
	}

	public List<GuiPatient> getGuiPatientList() {
		return guiPatientList;
	}

	public void setGuiPatientList(List<GuiPatient> guiPatientList) {
		this.guiPatientList = guiPatientList;
	}

	public GuiPagination getGuiPagination() {
		return guiPagination;
	}

	public void setGuiPagination(GuiPagination guiPagination) {
		this.guiPagination = guiPagination;
	}

	public boolean isExistMonthAppointmentMap() {
		return monthAppointmentMap != null;
	}
	
	public Map<Integer, List<GuiAppointment>> getMonthAppointmentMap() {
		return monthAppointmentMap;
	}

	public void setMonthAppointmentMap(
			Map<Integer, List<GuiAppointment>> monthAppointmentMap) {
		this.monthAppointmentMap = monthAppointmentMap;
	}
	
	public boolean hasExistGuiAppointmentList() {
		return (guiAppointmentList != null && guiAppointmentList.size() > 0);
	}
	
}
